#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<time.h>
#include<sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>

//  spinlock and mutex

#define LOOP_COUNT 10
#define THREAD_NUM 10

#define GLOBAL_LOOP_TIMES 10000

pthread_spinlock_t spinlock;
pthread_mutex_t mutex;

static int x = 0;

void *spinlock_sync(void *argc){
    for(int i=0; i< LOOP_COUNT; i++){
        pthread_spin_lock(&spinlock);
        x++;
        pthread_spin_unlock(&spinlock);
    }
}

void *mutex_sync(void *argc){
    for(int i=0; i< LOOP_COUNT; i++){
        pthread_mutex_lock(&mutex);
        x++;
        pthread_mutex_unlock(&mutex);
    }
}



int main(){

    double mutex_time_sum;
    double spinlock_time_sum;


    for(int i=0; i< GLOBAL_LOOP_TIMES; i++){
        if(pthread_spin_init(&spinlock, PTHREAD_PROCESS_SHARED) != 0){
            printf("spinlock init error\n");
            exit(1);
        }
        if(pthread_mutex_init(&mutex, NULL) != 0){
            printf("mutex init error\n");
            exit(1);
        }

        pthread_t tid[THREAD_NUM];
        int ret;
        time_t start, end; // for time statistic.

        // mutex
        start = clock();
        for(int i=0; i< THREAD_NUM; i++){
            ret = pthread_create(&(tid[i]), NULL, mutex_sync, NULL);
            if(ret != 0){
                printf("thread[%d] create error\n", i);
                exit(1);
            }
        }
        for(int i=0; i< THREAD_NUM; i++){
            pthread_join(tid[i], NULL);
        }
        end = clock();
        
        // printf("after mutex synced thread, x = %d, time costed:%f\n", x, (double)(end - start)/CLOCKS_PER_SEC);
        mutex_time_sum += (double)(end - start)/CLOCKS_PER_SEC;
        // spinlock 
        start = clock();
        for(int i = 0; i < THREAD_NUM; i++){
            ret = pthread_create(&(tid[i]), NULL, spinlock_sync, NULL);
            if(ret != 0){
                printf("thread[%d] create error", i);
                exit(1);
            }
        }
        for(int i = 0; i < THREAD_NUM; i++){
            pthread_join(tid[i], NULL);
        }
        end = clock();

        // printf("after spinlock synced thread, x = %d, time costed:%f\n", x, (double)(end - start)/CLOCKS_PER_SEC);
        spinlock_time_sum += (double)(end - start)/CLOCKS_PER_SEC;
    }

    printf("mutex time cost avg:%f, spinlock time cost avg:%f\nloop times:%d\n", 
        mutex_time_sum/GLOBAL_LOOP_TIMES, spinlock_time_sum/GLOBAL_LOOP_TIMES, GLOBAL_LOOP_TIMES);

    return 0;

}